Goblin = class()

function Goblin:init(x, y)
    self.x = x
    self.y = y
    self.state = 'idle'
    self.heardX = 0
    self.heardY = 0
    self.fightTarget = nil
    self.dead = false -- TODO: Should this be a state?
    self.killsPlayer = true
end

function Goblin:update(world)
    -- Goblins are EXTREMELY SMART and have two ranges of sensing the player:
    -- Within 8 units of distance, they HEAR a player, and walk closer...
    -- Within 5 units of distance, they SEE a player (or are sure of where they
    -- are) and become angered, setting the player as their agro-target.
    -- States:
    --  Idle - will hang around picking its nails.
    --  Suspicious - will walk to the last point it heard something.
    --   Goblins are lazy so it won't do much extra searching - once it gets
    --   to the place it heard the potential threat, it'll go back to idling
    --   there, figuring that it'll hear if the threat comes back.
    --  Fight - will walk towards the threat to eat it.
    -- The goblin will ALWAYS prioritize chasing over checking out something
    -- suspicious, so if it sees a player it'll go and chase them right away.

    if self.state == 'idle' or self.state == 'suspicious' then
        local seePlayer = self:findPlayer(world, 5)
        if seePlayer ~= nil then
            self.fightTarget = seePlayer
            self.state = 'fight'
        end
    end

    if self.state == 'fight' then
        if distanceBetweenPoints(self, self.fightTarget) > 8 then
            self.fightTarget = nil
            self.state = 'idle'
        else
            self:walkTowards(world, self.fightTarget.x, self.fightTarget.y)
        end
    end

    if self.state == 'idle' or self.state == 'suspicious' then
        local hearPlayer = self:findPlayer(world, 8)
        if hearPlayer ~= nil then
            self.heardX = hearPlayer.x
            self.heardY = hearPlayer.y
            self.state = 'suspicious'
        end
    end

    if self.state == 'suspicious' then
        -- If we bump into a wall, forget what we were doing and stop
        -- searching for the player.
        if not self:walkTowards(world, self.heardX, self.heardY) then
            self.heardX = 0
            self.heardY = 0
            self.state = 'idle'
        end
    end

    local hearPlayer = self:findPlayer(world, 8)
    local seePlayer = self:findPlayer(world, 5)

    if self.agroTarget == nil and seePlayer ~= nil then
        self.agroTarget = seePlayer
    end

    if self.pattern ~= nil then
        self.pattern:update(world)

        if self.pattern.done then
            self.pattern = nil
        end
    end

    self:testDead(world)
end

function Goblin:testDead(world)
    -- defined in player.lua, should be moved maybe
    if testColl(world.bullets, self.x, self.y) then
        self.dead = true
    end
end

function Goblin:findPlayer(world, distance)
    if distanceBetweenPoints(self, world.player) <= distance then
        return world.player
    else
        return nil
    end
end

function Goblin:walkTowards(world, x, y)
    -- Occasionally stumble!
    if love.math.random(1, 6) == 1 then
        return true -- true so we don't quit the suspicious state.
    end

    -- Go either horizontal or vertical, prioritizing the further distance or
    -- horizontal if they are equal. If we bump into a wall while moving hori-
    -- zontally, try moving vertically.
    local success = false
    function horizontal()
        return goToWithoutTouchingAnything(self, world,
            self.x + sign(x - self.x), self.y
        )
    end
    if math.abs(self.x - x) > math.abs(self.y - y) then
        success = horizontal()
    end
    if not success then
        success = goToWithoutTouchingAnything(self, world,
            self.x, self.y + sign(y - self.y)
        )
    end
    if not success then
        success = horizontal()
    end
    return success
end

function Goblin:draw(text)
    text[self.y][self.x] = {
        char = 'G',
        color = ({idle=COLOR.WHITE, suspicious=COLOR.YELLOW, fight=COLOR.RED})[self.state]
    }
end
